package com.xinyue.design.simpleFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 实现简单工厂的难点就在于 "如何选择"实现，下面讲到了几种传递参数的方法，那都是静态的参数，还可以实现成为动态的参数。
 * 比如：在运行期间，由工厂去读取某个内存的值，或者是去读取数据库中的值，然后根据这个值来选择具体的实现等等。
 */
public class ApiFactory {

	//私有化工厂类的构造方法，使用静态方法来创建接口实现类。
	private ApiFactory() {
		
	}
	
	// 工厂方法，根据不同的情况创建具体的实例。
	/**实现方式1：参数法。
	 * 这种实现方式灵活，缺点是新增加实现类的时候，就必须添加新的if else。不符合开闭原则。 
	 */
	public static Api createApi(int type) {
		
		Api api = null;
		if(1 == type) {
			api = new ApiUserImpl();
		}else {
			api = new ApiAdminImpl();
		}
		
		return api;
	}
	
	/**实现方式2：配置文件法。
	 * 这种实现方式是通过配置文件灵活添加新的实现类。
	 * 优点：不需要日后修改工厂类，通过配置文件即可维护接口对象实现关系。
	 */
	public static Api createApi(String type) {
		//要创建的实例名
		String className = "";
		
		//直接读取配置文件来获取需要创建实例的类
		Properties p = new Properties();
		InputStream in = null;
		try {
			in = ApiFactory.class.getResourceAsStream("factory.properties");
			p.load(in);
			
			className = p.getProperty(type);
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} finally{
			try {
				in.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
		}
		
		Api api = null;
		try {
			//通过反射机制创建实例对象
			api = (Api)Class.forName(className).newInstance();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		
		return api;
	}
	
	/**实现方式3：判断法+配置文件法。
	 * 这种实现方式是读取某个内存的值，或者是去读取数据库中的值，然后根据这个值，并通过配置文件灵活添加新的实现类。
	 * 优点：不需要日后修改工厂类，不需要传递参数，只维护配置文件和判断方式。
	 */
	public static Api createApi() {
		//要创建的实例名
		String className = "";
		
		String type = "";
		/**这里写获取type的方式。比如读取某个内存的值，或者是去读取数据库中的值。
		 * 例子：根据权限选择不同的实现类。
		 * 在数据库(或者其他地方如session、内存等)中读取用户的权限，根据用户权限读取配置文件的实现类。
		 */
		
		//直接读取配置文件来获取需要创建实例的类
		Properties p = new Properties();
		InputStream in = null;
		try {
			in = ApiFactory.class.getResourceAsStream("factory.properties");
			p.load(in);
			
			className = p.getProperty(type);
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} finally{
			try {
				in.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
		}
		
		Api api = null;
		try {
			//通过反射机制创建实例对象
			api = (Api)Class.forName(className).newInstance();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		
		return api;
	}
}
